/**
 *****************************************************************************************************
 * @copyright	(c)  Shenzhen Saiyuan Microelectronics Co., Ltd
 * @file	         SysFunVarDefine.c
 * @author
 * @version
 * @date
 * @brief	         Store var control and function control define
 * @details
 *****************************************************************************************************
 * @attention
 *
 *****************************************************************************************************
 */
#include "SC_Init.h"
#include "SC_it.h"
#include "..\Drivers\SCDriver_list.h"
#include "HeadFiles\SysFunVarDefine.h"
#include "HeadFiles\userHeadFolder\oledfont.h"
#include <stdio.h>
#include <stdarg.h>
//**********************************************************************
/**************************************Generated by EasyCodeCube*************************************/
// Forbid editing areas between the labels !!!

/*************************************.Generated by EasyCodeCube.************************************/
static uint8_t OLED_GRAM[128][8];
volatile unsigned char TWI0Flag = 0;
unsigned char TWI0SendData = 0;
unsigned char US0_UART_ReceiveData = 0;
int Light_Choose = 4;
void delay(uint16_t cnt)
{
    /*<UserCodeStart>*/ /*<SinOne-Tag><65>*/
    while (cnt--)
        ;
    /*<UserCodeEnd>*/ /*<SinOne-Tag><65>*/
}
////????
////??OLED??????????????/????dat??????????????????mode 0??????  1:????
void oled_write_byte(uint8_t dat, uint8_t mode)
{
    /*<UserCodeStart>*/ /*<SinOne-Tag><75>*/
    TWI_Start();
    TWI_SendByte(0x78);
    if (mode)
    {
        TWI_SendByte(0x40);
    }
    else
    {
        TWI_SendByte(0x00);
    }
    TWI_SendByte(dat);
    TWI_Stop();

    /*<UserCodeEnd>*/ /*<SinOne-Tag><75>*/
}
/**
 * @brief          cursor set to (x,y) point
 * @param[in]      x:X-axis, from 0 to 127
 * @param[in]      y:Y-axis, from 0 to 7
 * @retval         none
 */

void OLED_set_pos(uint8_t x, uint8_t y)
{
    oled_write_byte((0xb0 + y), OLED_CMD);               // set page address y
    oled_write_byte(((x & 0xf0) >> 4) | 0x10, OLED_CMD); // set column high address
    oled_write_byte((x & 0x0f), OLED_CMD);               // set column low address
}
void OLED_Clear(void)
{
    /*<UserCodeStart>*/ /*<SinOne-Tag><66>*/
    uint8_t i, n;
    for (i = 0; i < 8; i++)
    {
        oled_write_byte(0xb0 + i, OLED_CMD);
        oled_write_byte(0x00, OLED_CMD);
        oled_write_byte(0x10, OLED_CMD);
        for (n = 0; n < 128; n++)
        {
            oled_write_byte(0, OLED_DATA);
        }
    }

    /*<UserCodeEnd>*/ /*<SinOne-Tag><66>*/
}
////OLED???????????/??????
void OLED_ColorTurn(uint8_t ColorValue)
{
    /*<UserCodeStart>*/ /*<SinOne-Tag><67>*/
    if (ColorValue == 0)
    {
        oled_write_byte(0xA6, OLED_CMD);
    }
    if (ColorValue == 1)
    {
        oled_write_byte(0xA7, OLED_CMD);
    }

    /*<UserCodeEnd>*/ /*<SinOne-Tag><67>*/
}

/**
 * @brief          turn off OLED display
 * @param[in]      none
 * @retval         none
 */
/**
 * @brief          ???OLED???
 * @param[in]      none
 * @retval         none
 */
void OLED_display_off(void)
{
    oled_write_byte(0x8d, OLED_CMD);
    oled_write_byte(0x10, OLED_CMD);
    oled_write_byte(0xae, OLED_CMD);
}

/**
 * @brief          turn on OLED display
 * @param[in]      none
 * @retval         none
 */
/**
 * @brief          ??OLED???
 * @param[in]      none
 * @retval         none
 */

void OLED_display_on(void)
{
    oled_write_byte(0x8d, OLED_CMD);
    oled_write_byte(0x14, OLED_CMD);
    oled_write_byte(0xaf, OLED_CMD);
}
////OLED???????????/??????
void OLED_DisplayTurn(uint8_t TurnValue)
{
    /*<UserCodeStart>*/ /*<SinOne-Tag><71>*/
    if (TurnValue == 0)
    {
        oled_write_byte(0xC8, OLED_CMD);
        oled_write_byte(0xA1, OLED_CMD);
    }
    if (TurnValue == 1)
    {
        oled_write_byte(0xC0, OLED_CMD);
        oled_write_byte(0xA0, OLED_CMD);
    }

    /*<UserCodeEnd>*/ /*<SinOne-Tag><71>*/
}

////???????????? SendByte??????????????
void TWI_SendByte(uint8_t SendByte)
{
    /*<UserCodeStart>*/ /*<SinOne-Tag><78>*/
    TWI_SendData(TWI0, SendByte);
    while (!TWI0Flag)
        ;
    TWI0Flag = 0;

    /*<UserCodeEnd>*/ /*<SinOne-Tag><78>*/
}

////???????????
void TWI_Start(void)
{
    /*<UserCodeStart>*/ /*<SinOne-Tag><79>*/
    TWI_GenerateSTART(TWI0, ENABLE);
    while (!TWI0Flag)
        ;
    TWI0Flag = 0;
    delay(200);

    /*<UserCodeEnd>*/ /*<SinOne-Tag><79>*/
}
////TWI??????????
void TWI_Stop(void)
{
    /*<UserCodeStart>*/ /*<SinOne-Tag><80>*/
    TWI_GenerateSTOP(TWI0, ENABLE);
    delay(1300);

    /*<UserCodeEnd>*/ /*<SinOne-Tag><80>*/
}
/**
 * @brief          ?????????
 * @param[in]      row: ?????????
 * @param[in]      col: ?????????
 * @param[in]      chr: ???
 * @retval         none
 */
void OLED_show_char(uint8_t row, uint8_t col, uint8_t chr)
{
    uint8_t x = col * 6;
    uint8_t y = row * 12;
    uint8_t temp, t, t1;
    uint8_t y0 = y;
    chr = chr - ' ';

    for (t = 0; t < 12; t++)
    {
        temp = asc2_1206[chr][t];

        for (t1 = 0; t1 < 8; t1++)
        {
            if (temp & 0x80)
                OLED_draw_point(x, y, PEN_WRITE);
            else
                OLED_draw_point(x, y, PEN_CLEAR);

            temp <<= 1;
            y++;
            if ((y - y0) == 12)
            {
                y = y0;
                x++;
                break;
            }
        }
    }
}
/**
 * @brief          ???????????
 * @param[in]      row: ???????????
 * @param[in]      col: ???????????
 * @param[in]      chr: ?????
 * @retval         none
 */
void OLED_show_string(uint8_t row, uint8_t col, uint8_t *chr)
{
    uint8_t n = 0;

    while (chr[n] != '\0')
    {
        OLED_show_char(row, col, chr[n]);
        col++;

        if (col > 20)
        {
            col = 0;
            row += 1;
        }
        n++;
    }
}
/***********????????????????BMP??128??64?????????(x,y),x?????0??127??y???????0??7*****************/
// void OLED_Draw_Picture(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char *BMP)
// {
//     unsigned int j = 0;
//     unsigned char x, y;

//     if (y1 % 8 == 0)
//         y = y1 / 8;
//     else
//         y = y1 / 8 + 1;
//     for (y = y0; y < y1; y++)
//     {
//         OLED_set_pos(x0, y);
//         for (x = x0; x < x1; x++)
//         {
//             oled_write_byte(BMP[j++], OLED_DATA);
//         }
//     }
// } // 128*8
/******************************************************************************************************
 *???????????????????????????????????????x????0~127  y?????????0~6 input?????
 *???????
 ******************************************************************************************************/
void OLED_ShowByte(uint8_t x, uint8_t y, uint8_t input)
{
    unsigned char SwapValue = 0x00;
    int SwapNumber;
    for (SwapNumber = 0; SwapNumber < 8; SwapNumber++) // ?????????????????????
    {
        if (input & (0x01 << SwapNumber))
            SwapValue |= (0x80 >> SwapNumber);
    }
    OLED_set_pos(x, y);
    oled_write_byte(SwapValue, OLED_DATA); // ?????????????
}
/**
  * @brief          operate the graphic ram(size: 128*8 char)
  * @param[in]      pen: the type of operate.
                    PEN_CLEAR: set ram to 0x00
                    PEN_WRITE: set ram to 0xff
                    PEN_INVERSION: bit inversion
  * @retval         none
  */
/**
  * @brief          ????GRAM???(128*8char????)
  * @param[in]      pen: ????????.
                    PEN_CLEAR: ?????0x00
                    PEN_WRITE: ?????0xff
                    PEN_INVERSION: ???????
  * @retval         none
  */
void OLED_operate_gram(pen_typedef pen)
{
    uint8_t i, n;

    for (i = 0; i < 8; i++)
    {
        for (n = 0; n < 128; n++)
        {
            if (pen == PEN_WRITE)
            {
                OLED_GRAM[n][i] = 0xff;
            }
            else if (pen == PEN_CLEAR)
            {
                OLED_GRAM[n][i] = 0x00;
            }
            else
            {
                OLED_GRAM[n][i] = 0xff - OLED_GRAM[n][i];
            }
        }
    }
}

/**
  * @brief          draw one bit of graphic raw, operate one point of screan(128*64)
  * @param[in]      x: x-axis, [0, X_WIDTH-1]
  * @param[in]      y: y-axis, [0, Y_WIDTH-1]
  * @param[in]      pen: type of operation,
                        PEN_CLEAR: set (x,y) to 0
                        PEN_WRITE: set (x,y) to 1
                        PEN_INVERSION: (x,y) value inversion
  * @retval         none
  */

void OLED_draw_point(int8_t x, int8_t y, pen_typedef pen)
{
    uint8_t page = 0, row = 0;

    /* check the corrdinate */
    if ((x < 0) || (x > (X_WIDTH - 1)) || (y < 0) || (y > (Y_WIDTH - 1)))
    {
        return;
    }
    page = y / 8;
    row = y % 8;

    if (pen == PEN_WRITE)
    {
        OLED_GRAM[x][page] |= 1 << row;
    }
    else if (pen == PEN_INVERSION)
    {
        OLED_GRAM[x][page] ^= 1 << row;
    }
    else
    {
        OLED_GRAM[x][page] &= ~(1 << row);
    }
}
/**
 * @brief          draw a line from (x1, y1) to (x2, y2)
 * @param[in]      x1: the start point of line
 * @param[in]      y1: the start point of line
 * @param[in]      x2: the end point of line
 * @param[in]      y2: the end point of line
 * @param[in]      pen: type of operation,PEN_CLEAR,PEN_WRITE,PEN_INVERSION.
 * @retval         none
 */
/**
 * @brief          ???????????(x1,y1)??(x2,y2)
 * @param[in]      x1: ???
 * @param[in]      y1: ???
 * @param[in]      x2: ???
 * @param[in]      y2: ???
 * @param[in]      pen: ????????,PEN_CLEAR,PEN_WRITE,PEN_INVERSION.
 * @retval         none
 */

void OLED_draw_line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, pen_typedef pen)
{
    uint8_t col = 0, row = 0;
    uint8_t x_st = 0, x_ed = 0, y_st = 0, y_ed = 0;
    float k = 0.0f, b = 0.0f;

    if (y1 == y2)
    {
        (x1 <= x2) ? (x_st = x1) : (x_st = x2);
        (x1 <= x2) ? (x_ed = x2) : (x_ed = x1);

        for (col = x_st; col <= x_ed; col++)
        {
            OLED_draw_point(col, y1, pen);
        }
    }
    else if (x1 == x2)
    {
        (y1 <= y2) ? (y_st = y1) : (y_st = y2);
        (y1 <= y2) ? (y_ed = y2) : (y_ed = y1);

        for (row = y_st; row <= y_ed; row++)
        {
            OLED_draw_point(x1, row, pen);
        }
    }
    else
    {
        k = ((float)(y2 - y1)) / (x2 - x1);
        b = (float)y1 - k * x1;

        (x1 <= x2) ? (x_st = x1) : (x_st = x2);
        (x1 <= x2) ? (x_ed = x2) : (x_ed = x2);

        for (col = x_st; col <= x_ed; col++)
        {
            OLED_draw_point(col, (uint8_t)(col * k + b), pen);
        }
    }
}
/**
 * @brief          send the data of gram to oled sreen
 * @param[in]      none
 * @retval         none
 */
/**
 * @brief          ?????????OLED??GRAM
 * @param[in]      none
 * @retval         none
 */
void OLED_refresh_gram(void)
{
    uint8_t i, n;

    for (i = 0; i < 8; i++)
    {
        OLED_set_pos(0, i);
        for (n = 0; n < 128; n++)
        {
            oled_write_byte(OLED_GRAM[n][i], OLED_DATA);
        }
    }
}
/**
 * @brief          show the logo of RoboMaster
 * @param[in]      none
 * @retval         none
 */
/**
 * @brief          ???RM??LOGO
 * @param[in]      none
 * @retval         none
 */
void OLED_LOGO(void)
{
    uint8_t temp_char = 0;
    uint8_t x = 0, y = 0;
    uint8_t i = 0;
    OLED_operate_gram(PEN_CLEAR);

    for (; y < 64; y += 8)
    {
        for (x = 0; x < 128; x++)
        {
            temp_char = LOGO_BMP[x][y / 8];
            for (i = 0; i < 8; i++)
            {
                if (temp_char & 0x80)
                {
                    OLED_draw_point(x, y + i, PEN_WRITE);
                }
                else
                {
                    OLED_draw_point(x, y + i, PEN_CLEAR);
                }
                temp_char <<= 1;
            }
        }
    }
    OLED_refresh_gram();
}
////?????OLED????
void OLED_Init(void)
{
    /*<UserCodeStart>*/ /*<SinOne-Tag><72>*/
    oled_write_byte(0xFD, OLED_CMD);
    oled_write_byte(0x12, OLED_CMD);
    oled_write_byte(0xAE, OLED_CMD); //--turn off oled panel
    oled_write_byte(0xd5, OLED_CMD); //--set display clock divide ratio/oscillator frequency
    oled_write_byte(0xA0, OLED_CMD);
    oled_write_byte(0xA8, OLED_CMD); //--set multiplex ratio(1 to 64)
    oled_write_byte(0x3f, OLED_CMD); //--1/64 duty
    oled_write_byte(0xD3, OLED_CMD); //-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
    oled_write_byte(0x00, OLED_CMD); //-not offset
    oled_write_byte(0x40, OLED_CMD); //--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
    oled_write_byte(0xA1, OLED_CMD); //--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
    oled_write_byte(0xC8, OLED_CMD); // Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
    oled_write_byte(0xDA, OLED_CMD); //--set com pins hardware configuration
    oled_write_byte(0x12, OLED_CMD);
    oled_write_byte(0x81, OLED_CMD); //--set contrast control register
    oled_write_byte(0x7F, OLED_CMD); // Set SEG Output Current Brightness
    oled_write_byte(0xD9, OLED_CMD); //--set pre-charge period
    oled_write_byte(0x82, OLED_CMD); // Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
    oled_write_byte(0xDB, OLED_CMD); //--set vcomh
    oled_write_byte(0x34, OLED_CMD); // Set VCOM Deselect Level
    oled_write_byte(0xA4, OLED_CMD); // Disable Entire Display On (0xa4/0xa5)
    oled_write_byte(0xA6, OLED_CMD); // Disable Inverse Display On (0xa6/a7)
    OLED_Clear();
    // OLED_WR_Byte(0xAF, OLED_CMD);

    OLED_ColorTurn(0);
    OLED_DisplayTurn(0);
    OLED_display_off();
    OLED_display_on();
    /*<UserCodeEnd>*/ /*<SinOne-Tag><72>*/
}
/**
 * @brief Delay
 *
 */

/**
 *  ????????   ?????????
 *   ??????    ??Delay_ms();
 *   ????      ??ms ????72M?????? ms<=1864
 *   ?????    ????
 **/

void Delay_ms(uint32_t ms)
{
    uint32_t Temp;
    SysTick->LOAD = ms * 4000;                // ??????????
    SysTick->VAL = 0x00;                      // ???????????
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // ?????????
    // ??????????????????????????????????????????
    do
    {
        Temp = SysTick->CTRL; // ?????????????
    } while ((Temp & 0x01) && !(Temp & (1 << 16))); // CTRL 16???????????1
    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // ???????
    SysTick->VAL = 0x00;                       // ???????????
}
/**
 *  ????????   ?????????
 *   ??????    ??Delay_ms();
 *   ????      ??ms ????72M?????? ms<=1864
 *   ?????    ????
 **/

void Delay_us(uint32_t us)
{
    uint32_t Temp;
    SysTick->LOAD = us * 4;                   // ??????????
    SysTick->VAL = 0x00;                      // ???????????
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // ?????????
    // ??????????????????????????????????????????
    do
    {
        Temp = SysTick->CTRL; // ?????????????
    } while ((Temp & 0x01) && !(Temp & (1 << 16))); // CTRL 16???????????1
    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // ???????
    SysTick->VAL = 0x00;                       // ???????????
}
/**
 * @brief          formatted output in oled 128*64
 * @param[in]      row: row of character string begin, 0 <= row <= 4;
 * @param[in]      col: column of character string begin, 0 <= col <= 20;
 * @param          *fmt: the pointer to format character string
 * @note           if the character length is more than one row at a time, the extra characters will be truncated
 * @retval         none
 */
void OLED_printf(uint8_t row, uint8_t col, const char *fmt, ...)
{
    static uint8_t LCD_BUF[128] = {0};
    static va_list ap;
    uint8_t remain_size = 0;

    if ((row > 4) || (col > 20))
    {
        return;
    }
    va_start(ap, fmt);

    vsprintf((char *)LCD_BUF, fmt, ap);

    va_end(ap);

    remain_size = 21 - col;

    LCD_BUF[remain_size] = '\0';

    OLED_show_string(row, col, LCD_BUF);
}

uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    switch (msg)
    {
    case U8X8_MSG_GPIO_AND_DELAY_INIT:

        break;
    case U8X8_MSG_DELAY_NANO: // delay arg_int * 1 nano second
        break;
    case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
        __NOP();
        break;
    case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
        Delay_us(10);
        break;
    case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
        Delay_ms(1);
        break;
    case U8X8_MSG_DELAY_I2C: // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
        Delay_us(10);
        break; // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us

    case U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pin
        if (arg_int)
            GPIO_SetBits(GPIOA, GPIO_Pin_6);
        else
            GPIO_ResetBits(GPIOA, GPIO_Pin_6);
        break;                   // arg_int=1: Input dir with pullup high for I2C clock pin
    case U8X8_MSG_GPIO_I2C_DATA: // arg_int=0: Output low at I2C data pin
        if (arg_int)
            GPIO_SetBits(GPIOA, GPIO_Pin_5);
        else
            GPIO_ResetBits(GPIOA, GPIO_Pin_5);
        break; // arg_int=1: Input dir with pullup high for I2C data pin
    }
    return 1;
}

void u8g2Init(u8g2_t *u8g2)
{
    u8g2_Setup_ssd1306_i2c_128x64_noname_f(u8g2, U8G2_R0, u8x8_byte_i2c, u8x8_gpio_and_delay);
    u8g2_InitDisplay(u8g2);
    u8g2_SetPowerSave(u8g2, 0);
    u8g2_ClearBuffer(u8g2);
}
// uint8_t u8x8_byte_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
// {
//     static uint8_t buffer[32]; /* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */
//     static uint8_t buf_idx;
//     uint8_t *data = (uint8_t *)arg_ptr;
//     switch (msg)
//     {
//     case U8X8_MSG_BYTE_SEND:
//         while (arg_int-- > 0)
//         {
//             TWI_SendData(TWI0, *data++);
//             while (!TWI_GetFlagStatus(TWI1, TWI_FLAG_TXRXnE))
//                 ;
//         }
//         break;
//     case U8X8_MSG_BYTE_INIT:
//         /* add your custom code to init i2c subsystem */
//         break;
//     case U8X8_MSG_BYTE_SET_DC:
//         /* ignored for i2c */
//         break;
//     case U8X8_MSG_BYTE_START_TRANSFER:
//         TWI_GenerateSTART(TWI0, ENABLE);
//         while (TWI_GetStateMachine(TWI1) != TWI_Master_SendAddress)
//             ;
//         TWI_Send7bitAddress(TWI0, 0x78, TWI_Command_Write);
//         while (TWI_GetStateMachine(TWI1) != TWI_Master_SendData)
//             ;

//     case U8X8_MSG_BYTE_END_TRANSFER:
//         TWI_GenerateSTOP(TWI0, ENABLE);
//         break;
//     default:
//         return 0;
//     }
//     return 1;
// }

uint8_t u8x8_byte_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    static uint8_t buffer[32]; /* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */
    static uint8_t buf_idx;
    uint8_t *data;

    switch (msg)
    {
    case U8X8_MSG_BYTE_SEND:
        data = (uint8_t *)arg_ptr;
        while (arg_int > 0)
        {
            buffer[buf_idx++] = *data;
            data++;
            arg_int--;
        }
        break;
    case U8X8_MSG_BYTE_INIT:
        break;
    case U8X8_MSG_BYTE_SET_DC:
        break;
    case U8X8_MSG_BYTE_START_TRANSFER:
        buf_idx = 0;
        break;
    case U8X8_MSG_BYTE_END_TRANSFER:
        TWI_Send7bitAddress(TWI0, 0x78, TWI_Command_Write);
        for (uint8_t i = 0; i < buf_idx; i++)
        {
            TWI_SendData(TWI0, buffer[i]);
        }
        break;
    default:
        return 0;
    }
    return 1;
}
void OLED_Draw_Picture(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char BMP[])
{
    unsigned int j = 0; // 定义变量，用于指�?BMP 数组
    unsigned char x, y; // 定义变量，分别表示当前的列和�?
                        // 判断终止页是否为 8 的整数倍，确定绘制的页�?
    if (y1 % 8 == 0)
        y = y1 / 8;
    else
        y = y1 / 8 + 1;

    // 遍历从起始页到终止页的每一�?
    for (y = y0; y < y1; y++) // 从起始页开始，画到终止�?
    {
        // 遍历每一�?
        for (x = x0; x < x1; x++) // 画从 x0 �?x1 的每�?
        {
            // 取出当前字节的数据，并设置相应位置的�?
            unsigned char byte = BMP[j++]; // 取出一个字节，包含 8 个像�?
            // 遍历字节中的每个像素�?
            for (unsigned char bit = 0; bit < 8; bit++)
            {
                // 计算当前点的屏幕坐标 (x, y * 8 + bit)
                int current_y = y * 8 + bit;

                // 确保仅修改图像区域内的点，避免影响字体显示区�?
                if (current_y < Y_WIDTH)
                { // Y_WIDTH 是屏幕的高度，防止越�?                    // 根据当前字节的值设置对应的点，若该位为 1，绘制点，若�?0，清除点
                    if ((byte >> bit) & 1)
                    {
                        OLED_draw_point(x, current_y, PEN_WRITE); // 设置该点�?1 (绘制)
                    }
                    else
                    {
                        OLED_draw_point(x, current_y, PEN_CLEAR); // 设置该点�?0 (清除)
                    }
                }
            }
        }
    }
}
/**
 * @brief          反转 OLED_GRAM 数组中的指定区域内的显示
 * @param[in]      x0: 区域起始�?x 坐标
 * @param[in]      y0: 区域起始�?y 坐标
 * @param[in]      x1: 区域结束�?x 坐标
 * @param[in]      y1: 区域结束�?y 坐标
 * @retval         none
 */
void OLED_Reverse(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1)
{
    unsigned char x, y, bit;
    unsigned char page, row;

    // 遍历区域的每一�?(x0 �?x1)
    for (x = x0; x < x1; x++)
    {
        // 遍历区域的每一页（y0 �?y1�?        for (y = y0 / 8; y < (y1 / 8) + 1; y++) // y0 / 8 �?y1 / 8，按页处�?        {
        // 计算当前页面的行位置
        page = y;
        for (row = 0; row < 8; row++) // 遍历每一�?            {
        // 确保该行是在目标区域�?                if ((y * 8 + row) >= y0 && (y * 8 + row) < y1)
        {
            // 反转对应�?OLED_GRAM 中的�?                    OLED_GRAM[x][page] ^= (1 << row);
        }
    }
}

void OLED_Shift_Up(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1)
{
    unsigned char x, y;
    unsigned char page_start, page_end;

    // 计算起始页和结束�?    page_start = y0 / 8;
    page_end = y1 / 8;

    // 遍历指定区域的每�?    for (x = x0; x < x1; x++)
    {
        // 对每一页进行操作，从起始页到结束页
        for (y = page_start; y < page_end; y++)
        {
            // 将当前页的值向上移动到上一�?            OLED_GRAM[x][y] = OLED_GRAM[x][y + 1];
        }

        // 清空最后一页（因为向上平移�?8 个像素，所以最后一页的数据不再需要）
        OLED_GRAM[x][page_end] = 0x00;
    }
}

/**
 * @brief          将指定区域的内容向下平移 8 个像�? * @param[in]      x0: 区域起始�?x 坐标
 * @param[in]      y0: 区域起始�?y 坐标
 * @param[in]      x1: 区域结束�?x 坐标
 * @param[in]      y1: 区域结束�?y 坐标
 * @retval         none
 */
void OLED_Shift_Down(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1)
{
    unsigned char x, y;
    unsigned char page_start, page_end;

    // 计算起始页和结束�?    page_start = y0 / 8;
    page_end = y1 / 8;

    // 遍历指定区域的每�?    for (x = x0; x < x1; x++)
    {
        // 对每一页进行操作，从结束页到起始页（反向移动）
        for (y = page_end; y > page_start; y--)
        {
            // 将当前页的值向下移动到下一�?            OLED_GRAM[x][y] = OLED_GRAM[x][y - 1];
        }

        // 清空顶部的页（因为向下平移了 8 个像素，所以顶部的页的数据不再需要）
        OLED_GRAM[x][page_start] = 0x00;
    }
}
